/*
 moxl - Modular XML Library
 Copyright (c) 2007, Malcolm Sparks

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package moxl.xpath.tokenizer;

import java.io.IOException;

import moxl.reader.LocateableReader;
import moxl.tokenizer.CodePage;
import moxl.tokenizer.Token;
import moxl.tokenizer.TokenReadyState;
import moxl.tokenizer.AbstractTokenizerState;
import moxl.tokenizer.TokenizerStateMachine;

public class XPathInNameOrNodeTypeState extends AbstractTokenizerState
{
	private static AbstractTokenizerState instance = new XPathInNameOrNodeTypeState();

	public static AbstractTokenizerState getInstance()
	{
		return instance;
	}

	@Override
	public void accept(TokenizerStateMachine stateMachine, Token token, LocateableReader reader) throws IOException
	{
		// potentially we may have a lot of whitespace
		reader.mark(8000);

		int character = reader.read();
		boolean interveningWhitespace = false;

		// skip any intervening whitespace
		while (CodePage.isWhitespace(character))
		{
			interveningWhitespace = true;
			character = reader.read();
		}

		if (character == -1)
		{
			reader.reset();
			token.setTokenType(XPathTokenTypes.NAME_TEST);
			stateMachine.changeState(TokenReadyState.getInstance());
		}
		else if (character == '(')
		{
			reader.reset();

			// Token is NodeType or FunctionName
			String image = token.getImage();
			if (image.equals("comment") || image.equals("text") || image.equals("processing-instruction") || image.equals("node"))
			{
				token.setTokenType(XPathTokenTypes.NODE_TYPE);
			}
			else
			{
				token.setTokenType(XPathTokenTypes.FUNCTION_NAME);
			}
			stateMachine.changeState(TokenReadyState.getInstance());
		}
		else if (character == ':')
		{
			int secondCharacter = reader.read();
			if (secondCharacter == ':')
			{
				// :: after NCName, that means we're an AxisName
				token.setTokenType(XPathTokenTypes.AXIS_NAME);
				stateMachine.changeState(TokenReadyState.getInstance());
			}
			else
			{
				throw new UnsupportedOperationException("What to do with a : in an NCName?");
			}
			reader.reset();
		}
		else if (CodePage.isNCNameChar(character) && !interveningWhitespace)
		{
			token.append(character);
		}
		else
		{
			reader.reset();

			if (StartState.isPrecedingTokenNotInSet(stateMachine.getPreviousToken()))
			{
				String image = token.getImage();
				if (isOperatorName(image))
				{
					token.setTokenType(XPathTokenTypes.OPERATOR);
				}
				else
				{
					token.setTokenType(XPathTokenTypes.ILLEGAL_CHARACTER);
				}
			}
			else
			{
				token.setTokenType(XPathTokenTypes.NAME_TEST);
			}
			stateMachine.changeState(TokenReadyState.getInstance());
		}
	}

	private boolean isOperatorName(String image)
	{
		return image.equals("and") || image.equals("or") || image.equals("mod") || image.equals("div");
	}
}
